package org.springframework.beans.factory.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.SingletonBeanRegistry;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * @Name DefaultSingletonBeanRegistry
 * @Description: 单例 Bean 实例容器 [默认实现] 类
 * 描述信息：实现了获取单例 Bean 实例的方法。
 * 扩展：新增了添加单例 Bean 实例的方法。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-03-14 14:40:52
 **/
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
    /**
     * Spring 容器单例 Bean 三级缓存方案：
     * 1. [一级缓存] 存放已经经历完整生命周期（创建、设置属性、初始化... ...）的单例 Bean 对象
     * 2. [二级缓存] 存放早期暴露出来（放入三级缓存中，以解决循环依赖问题）的单例 Bean 对象，Bean 的生命周期未结束（属性还未填充完成）。
     * 3. [三级缓存] 存放可以生成单例 Bean 的工厂。
     * 注意：非单例的 bean 是没有缓存的，不会将其放到其三级缓存方案中。
     */
    private Map<String, Object> singletonObjects = new HashMap<>();
    private Map<String, Object> earlySingletonObjects = new HashMap<>();
    private Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();

    // 注册带有销毁方法的 Bean 实例缓存
    private final Map<String, DisposableBean> disposableBeans = new HashMap<>();

    @Override
    public void addSingleton(String beanName, Object singletonObject) {
        singletonObjects.put(beanName, singletonObject);
        earlySingletonObjects.remove(beanName);
        singletonFactories.remove(beanName);
    }

    @Override
    public Object getSingleton(String beanName) {
        /**
         * 从 Bean 容器中获取单例 Bean 实例
         * --> 依次检查一级缓存 singletonObjects、二级缓存 earlySingletonObjects 和三级缓存 singletonFactories 中是否包含目标 Bean 实例。如果最后在三级缓存中包含该 Bean，则挪至二级缓存中，然后返回该 Bean。
         */
        Object singletonObject = singletonObjects.get(beanName);
        if (singletonObject == null) {
            singletonObject = earlySingletonObjects.get(beanName);
            if (singletonObject == null) {
                ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    // 从三级缓存存放进二级缓存
                    earlySingletonObjects.put(beanName, singletonObject);
                    singletonFactories.remove(beanName);
                }
            }
        }
        return singletonObject;
    }

    /**
     * 向三级缓存中添加单例工厂 Bean 实例
     *
     * @param beanName         Bean 名称
     * @param singletonFactory 单例工厂 Bean 实例
     * @version v1.0.0
     * @author lichao
     * @date 2024-04-12 14:50:34
     */
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        singletonFactories.put(beanName, singletonFactory);
    }

    /**
     * 注册带有销毁方法的 Bean, 即 Bean 继承自 DisposableBean 接口或有自定义的销毁方法
     *
     * @param beanName Bean 名称
     * @param bean     Bean 实例
     * @version v1.0.0
     * @author lichao
     * @date 2024-03-20 15:23:14
     */
    public void registerDisposableBean(String beanName, DisposableBean bean) {
        disposableBeans.put(beanName, bean);
    }

    @Override
    public void destroySingletons() {
        ArrayList<String> beanNames = new ArrayList<>(disposableBeans.keySet());
        for (String beanName : beanNames) {
            DisposableBean disposableBean = disposableBeans.remove(beanName);
            try {
                disposableBean.destory();
            } catch (Exception e) {
                throw new BeansException("Bean [" + beanName + "] 实例销毁失败!", e);
            }
        }
    }

}

